package org.quadraspace.model;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class MoteUtil {
	public static Mote generateFakeMoteWithID(String id) {
		Mote toRet = new Mote();
		toRet.setId(id);
		toRet.getBoard().setModel("Sun SPOT V3");
		toRet.getBoard().setVendor("Sun Microsystems");
		toRet.setLocation(new Location());
		Interface inf = new Interface();
		inf.setId("UDP Interface");
		inf.setType("UDP");
		inf.getAddress().setType("AF_INET");
		inf.getAddress().setValue("192.168.1.128");
		toRet.getInterfaces().add(inf);

		Sensor sen = new Sensor();
		sen.setModel("Therma3");
		sen.setVendor("Arcitec");
		sen.setId("sens1");
		sen.setType("thermometer");
		sen.getData().setQuantity("TEMPERATURE");
		Channel o = new Channel();
		o.setId("channelId");
		o.setMaxV(123.03);
		o.setMinV(0.0);
		o.setResolution(0.1);
		o.setMimetype("text/plain");
		o.setType(Channel.Type.FLOAT);
		o.setUnit("celsius degrees");
		o.setAccuracy(33.3);
		sen.getData().getChannels().add(o);
		toRet.getSensors().add(sen);
		return toRet;
	}

	public static void mergeMotes(Mote from, Mote into) {
		List<Class<?>> classes = new ArrayList<Class<?>>();
		classes.add(Mote.class);
		classes.add(Interface.class);
		classes.add(Channel.class);
		classes.add(Sensor.class);
		mergeObjects(from, into, classes);
	}

	public static void testMergeables(Class<?> fromC, Class<?> intoC) {
		if (!fromC.isAssignableFrom(intoC)) {
			throw new RuntimeException(
					"Trying to merge two incompatible classes!");
		}
	}

	public static void mergeObjects(Object from, Object into,
			List<Class<?>> domain) {
		try {
			testMergeables(from.getClass(), into.getClass());
			BeanInfo bi = Introspector.getBeanInfo(into.getClass());
			PropertyDescriptor[] properties = bi.getPropertyDescriptors();
			for (PropertyDescriptor p : properties) {
				//System.out.println("Method "+p.getName());
				//System.out.println("WriteMethod "+p.getWriteMethod());
				Method readMethod = p.getReadMethod();
				Method writeMethod = p.getWriteMethod();
				if (readMethod == null || writeMethod == null) continue;
				Object gotFrom = readMethod.invoke(from);
				Object gotInto = readMethod.invoke(into);
				if (gotFrom == null)
					continue;
				if (gotInto != null && domain.contains(gotFrom.getClass())) {
					mergeObjects(gotFrom, gotInto, domain);
				} else /*
						 * if (gotInto == null ||
						 * !domain.contains(gotFrom.getClass()))
						 */{
					//System.out.println("invoking"+writeMethod+" arg "+gotFrom);
					writeMethod.invoke(into, gotFrom);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
}
